package zzps.exeed.kernel.convert;

import zzps.exeed.kernel.convert.impl.*;
import zzps.exeed.kernel.tool.ClassTool;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.*;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.*;

public class ConverterRegistry {
    private static final ConverterRegistry INSTANCE = new ConverterRegistry();
    private Map<Type, Converter<?>> defaultConverterMap = new HashMap<>();
    private volatile Map<Type, Converter<?>> customConverterMap;

    private ConverterRegistry() {
        NumberConverter integerConverter = new NumberConverter(Integer.class);
        NumberConverter longConverter = new NumberConverter(Long.class);
        NumberConverter byteConverter = new NumberConverter(Byte.class);
        NumberConverter shortConverter = new NumberConverter(Short.class);
        NumberConverter floatConverter = new NumberConverter(Float.class);
        NumberConverter doubleConverter = new NumberConverter(Double.class);
        CharacterConverter characterConverter = new CharacterConverter();
        BooleanConverter booleanConverter = new BooleanConverter();
        StringConverter stringConverter = new StringConverter();
        //原始类型转换器
        defaultConverterMap.put(int.class, integerConverter);
        defaultConverterMap.put(long.class, longConverter);
        defaultConverterMap.put(byte.class, byteConverter);
        defaultConverterMap.put(short.class, shortConverter);
        defaultConverterMap.put(float.class, floatConverter);
        defaultConverterMap.put(double.class, doubleConverter);
        defaultConverterMap.put(char.class, characterConverter);
        defaultConverterMap.put(boolean.class, booleanConverter);
        //包装类转换器
        defaultConverterMap.put(Integer.class, integerConverter);
        defaultConverterMap.put(AtomicInteger.class, new NumberConverter(AtomicInteger.class));
        defaultConverterMap.put(Long.class, longConverter);
        defaultConverterMap.put(LongAdder.class, new NumberConverter(LongAdder.class));
        defaultConverterMap.put(AtomicLong.class, new NumberConverter(AtomicLong.class));// since 3.0.8
        defaultConverterMap.put(Byte.class, byteConverter);
        defaultConverterMap.put(Short.class, shortConverter);
        defaultConverterMap.put(Float.class, floatConverter);
        defaultConverterMap.put(Double.class, doubleConverter);
        defaultConverterMap.put(DoubleAdder.class, new NumberConverter(DoubleAdder.class));
        defaultConverterMap.put(Character.class, characterConverter);
        defaultConverterMap.put(Boolean.class, booleanConverter);
        defaultConverterMap.put(BigDecimal.class, new NumberConverter(BigDecimal.class));
        defaultConverterMap.put(BigInteger.class, new NumberConverter(BigInteger.class));
        defaultConverterMap.put(CharSequence.class, stringConverter);
        defaultConverterMap.put(String.class, stringConverter);
        // 日期时间
//        defaultConverterMap.put(Calendar.class, new CalendarConverter());
        defaultConverterMap.put(java.util.Date.class, new DateConverter(java.util.Date.class));
//        defaultConverterMap.put(java.sql.Date.class, new DateConverter(java.sql.Date.class));
//        defaultConverterMap.put(java.sql.Time.class, new DateConverter(java.sql.Time.class));
//        defaultConverterMap.put(java.sql.Timestamp.class, new DateConverter(java.sql.Timestamp.class));

        // 日期时间 JDK8+(since 5.0.0)
        defaultConverterMap.put(TemporalAccessor.class, new TemporalAccessorConverter(Instant.class));
        defaultConverterMap.put(Instant.class, new TemporalAccessorConverter(Instant.class));
        defaultConverterMap.put(LocalDateTime.class, new TemporalAccessorConverter(LocalDateTime.class));
        defaultConverterMap.put(LocalDate.class, new TemporalAccessorConverter(LocalDate.class));
        defaultConverterMap.put(LocalTime.class, new TemporalAccessorConverter(LocalTime.class));
        defaultConverterMap.put(ZonedDateTime.class, new TemporalAccessorConverter(ZonedDateTime.class));
        defaultConverterMap.put(OffsetDateTime.class, new TemporalAccessorConverter(OffsetDateTime.class));
        defaultConverterMap.put(OffsetTime.class, new TemporalAccessorConverter(OffsetTime.class));
        defaultConverterMap.put(DayOfWeek.class, new TemporalAccessorConverter(DayOfWeek.class));
        defaultConverterMap.put(Month.class, new TemporalAccessorConverter(Month.class));
        defaultConverterMap.put(MonthDay.class, new TemporalAccessorConverter(MonthDay.class));
//        defaultConverterMap.put(Period.class, new PeriodConverter());
//        defaultConverterMap.put(Duration.class, new DurationConverter());
    }

    public static ConverterRegistry get() {
        return INSTANCE;
    }

    public <T> T convert(Type type, Object value){
        if (type instanceof Class clazz){
            if (value.getClass() == clazz){
                return (T) value;
            }
        }
        if (type instanceof TypeReference<?>) {
            type = ((TypeReference<?>) type).getType();
        }
        Converter<T> converter = getConverter(type);
        if (converter != null){
            return converter.convert(value);
        }
        Class<T> rawClass = (Class<T>)ClassTool.getRawClass(type);
        if (rawClass == null){
            return (T) value;// 无法识别的泛型类型，按照Object处理
        }
        return convertSpecial(type,rawClass,value);
    }

    private <T> T convertSpecial(Type type, Class<T> rowType,Object value){
        // 集合转换（不可以默认强转）
        if (Collection.class.isAssignableFrom(rowType)) {
            final CollectionConverter collectionConverter = new CollectionConverter(type);
            return (T) collectionConverter.convert(value);
        }
        if (rowType.isInstance(value)) {
            return (T) value;
        }
        if (rowType.isArray()) {
            final ArrayConverter arrayConverter = new ArrayConverter(rowType);
            return (T) arrayConverter.convert(value);
        }
        return null;
    }

    private <T> Converter<T> getConverter(Type type){
        return (Converter<T>)defaultConverterMap.get(type);
    }
}
